<?PHP
/*
 * $Id: barge-mail.classes.php 139 2009-12-16 15:29:56Z namba0219 $
 * =============================================================================
 * Barge - Web application framework on PHP5
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 * =============================================================================
 * For more information, see http://barge.googlecode.com/
 */
namespace barge\mail;

use \Exception;

use barge\System;
use barge\io\File;
use barge\logging\LogFactory;
use barge\utils\ArrayList;
use barge\utils\ArrayUtils;
use barge\utils\Entry;
use barge\utils\String;
use barge\utils\StringBuffer;
use barge\utils\Timestamp;

/**
 * メール送信例外
 *
 * @version 1.0 2006/09/11
 * @author Kenji Namba
 * @since Barge 1.0 2006/09/11
 * @see Exception
 */
class SendMailException extends Exception
{
}

/**
 * 表示名付き、メールアドレス
 *
 * @version 1.0 2006/09/11
 * @author Kenji Namba
 * @since Barge 1.0 2006/09/11
 */
class Address
{
	/**
	 * @var string
	 */
	private $address;

	/**
	 * @var string
	 */
	private $name;

	/**
	 * @var string
	 */
	private $encoding;

	/**
	 * @var string
	 */
	private $transferEncoding;

	/**
	 * @param string $address
	 * @param string $name
	 * @param string $encoding
	 * @param string $transferEncoding
	 */
	public function __construct($address, $name = null, $encoding = null, $transferEncoding = null)
	{
		$this->address = $address;
		$this->name = $name;
		$this->encoding = $encoding;
		$this->transferEncoding = $transferEncoding;
	}

	/**
	 * @return string
	 */
	public function getName()
	{
		return $this->name;
	}

	/**
	 * @return string
	 */
	public function getEncoding()
	{
		return $this->encoding;
	}

	/**
	 * @return string
	 */
	public function getTransferEncoding()
	{
		return $this->transferEncoding;
	}

	/**
	 * @return string
	 */
	public function getAddress()
	{
		return $this->address;
	}
}

/**
 * @version 1.0 2006/09/11
 * @author Kenji Namba
 * @since Barge 1.0 2006/09/11
 */
class Header
{
	/**
	 * @var string
	 */
	private $value;

	/**
	 * @var string
	 */
	private $transferEncoding;

	/**
	 * @var string
	 */
	private $encoding;

	/**
	 * @param string $address
	 * @param string $name
	 * @param string $encoding
	 * @param string $transferEncoding
	 */
	public function __construct($value, $encoding = null, $transferEncoding = null)
	{
		$this->value = $value;
		$this->encoding = $encoding;
		$this->transferEncoding = $transferEncoding;
	}

	/**
	 * @return string
	 */
	public function getTransferEncoding()
	{
		return $this->transferEncoding;
	}

	/**
	 * @return string
	 */
	public function getEncoding()
	{
		return $this->encoding;
	}

	/**
	 * @return string
	 */
	public function getValue()
	{
		return $this->value;
	}
}

/**
 * メール本文
 * @version 1.0 2009/06/24
 * @author Kenji Namba
 * @since barge 1.3 2009/06/24
 */
class ContentBody
{
	/**
	 * コンテンツ
	 * @var string
	 */
	private $content;

	/**
	 * @var string
	 */
	private $transferEncoding;

	/**
	 * @var string
	 */
	private $contentType;

	/**
	 * ファイル名
	 * @var string
	 */
	private $fileName;

	/**
	 * @var string
	 */
	private $encoding;

	/**
	 * @param string $multipartType マルチパート形式
	 */
	public function __construct($content, $contentType = null, $fileName = null, $encoding = null, $transferEncoding = null)
	{
		$this->content = $content;
		$this->contentType = $contentType;
		$this->fileName = $fileName;
		$this->encoding = $encoding;
		$this->transferEncoding = $transferEncoding;
	}


	/**
	 * @return string
	 */
	public function getTransferEncoding()
	{
		return $this->transferEncoding;
	}

	/**
	 * @return string
	 */
	public function getEncoding()
	{
		return $this->encoding;
	}

	/**
	 * @return string
	 */
	public function getContent()
	{
		return $this->content;
	}

	/**
	 * @return string
	 */
	public function getContentType()
	{
		return $this->contentType;
	}

	/**
	 * @return string
	 */
	public function getFileName()
	{
		return $this->fileName;
	}

}

/**
 * マルチパートコンテンツ
 *
 * @version 1.0 2009/06/24
 * @author Kenji Namba
 * @since barge 1.3 2009/06/24
 */
class MultipartBody
{
		/**
	 * 通常
	 */
	const MULTIPART_MIXED = 'multipart/mixed';

	/**
	 * HTMLメールのような代替テキストとして扱う場合
	 */
	const MULTIPART_ALTERNATIVE = 'multipart/alternative';

	/**
	 * メディアファイルなどの複合コンテンツ
	 */
	const MULTIPART_PARALLEL = 'multipart/parallel';

	/**
	 * メーリングリストなど
	 */
	const MULTIPART_DIGEST = 'multipart/digest';

	/**
	 * マルチパートの内容
	 * @var ArrayList
	 */
	private $bodies;

	/**
	 * マルチパートMIME形式
	 * @var string
	 */
	private $multipartType;

	/**
	 * @param string $multipartType マルチパートMIME形式
	 */
	public function __construct($multipartType = self::MULTIPART_MIXED)
	{
		$this->multipartType = $multipartType;
		$this->bodies = new ArrayList();
	}


	/**
  	 * テキスト形式の本文を追加する
	 * @param string $text 本文
	 * @param string $contentType コンテントタイプ、HTMLメールを送信する場合は "text/html"
	 * @param string $encoding エンコーディング、省略された場合は{@link #setTextEncoding}で設定された
	 * 					ものが使用されます。
	 * @param string $transferEncoding 転送エンコーディング、省略された場合は{@link #setTextEncoding}で設定された
	 * 					ものが使用されます。
	 */
	public function addTextBody($text, $contentType = 'text/plain', $encoding = null, $transferEncoding = null)
	{
		$this->bodies->add(new ContentBody($text, $contentType, null, $encoding, $transferEncoding));
	}

	/**
  	 * ファイル形式の本文を追加する、通常の添付ファイルを実現したい場合は、{@link #setMultipartBody}を使用して
  	 * ください。
  	 *
	 * @param string $filepath 追加するファイルのパス
	 * @param string $contentType コンテントタイプ、追加するファイルのメディアタイプを指定します。
	 * @param string $fileName ファイル名、省略された場合は指定されたファイルパスのファイル名が使用されます
	 * @param string $transferEncoding 転送エンコーディング
	 * @throws barge\io\IOException ファイルが存在しない、読み込めない場合などにスローされる
	 */
	public function addFileBody($filepath, $contentType, $fileName = null, $transferEncoding = null)
	{
		$fileName = $fileName === null ? File::getBaseName($filepath) : $fileName;
		$content = File::getContents($filepath);
		$this->bodies->add(new ContentBody($content, $contentType, $fileName, null, $transferEncoding));
	}

	/**
	 * マルチパートコンテンツを追加する
	 * <pre>
	 * $body = new MultipartBody(MultipartBody::MULTIPART_ALTERNATIVE);
	 * $body->addTextBody('Hellow world!');
	 * $mailer->setMultipartBody($body);
	 * </pre>
	 *
	 * @param MultipartBody $body
	 */
	public function addMultipartBody(MultipartBody $body)
	{
		$this->bodies->add($body);
	}


	/**
	 * @return ArrayList
	 */
	public function getMultipartBodies()
	{
		return $this->bodies;
	}

	/**
	 * マルチパートタイプを返す
	 * @return string
	 */
	public function getMultipartType()
	{
		return $this->multipartType;
	}
}

/**
 * Mailer
 *
 * <pre>
 * $mailer = new Mailer('inquire');
 * $mailer->setTo('sample@mail.com');
 * $mailer->setFrom('sample@mail.com');
 * $mailer->setTextBody('Hellow world');
 * $mailer->send();
 * </pre>
 *
 * @version 1.0 2006/09/11
 * @author Kenji Namba
 * @since barge 1.0 2006/09/11
 */
class Mailer
{

	/**
	 * @var Header
	 */
	private $subject;

	/**
	 * @var string|Address
	 */
	private $from;

	/**
	 * @var Timestamp
	 */
	private $sentDate;

	/**
	 * @var ArrayList
	 */
	private $toList;

	/**
	 * @var ArrayList
	 */
	private $bccList;

	/**
	 * @var ArrayList
	 */
	private $ccList;

	/**
	 * @var mixex
	 */
	private $body;

	/**
	 * @var ArrayList
	 */
	private $replyToList;

	/**
	 * @var string
	 */
	private $headerEncoding;

	/**
	 * @var string
	 */
	private $headerTransferEncoding;

	/**
	 * @var string
	 */
	private $textEncoding;

	/**
	 * @var string
	 */
	private $textTransferEncoding;

	/**
	 * 追加のヘッダーリスト
	 * @var HashMap
	 */
	private $headers;

	/**
	 * 引数のプロファルは、From, To, Bcc などの設定情報を設定レポジトリから取得する
	 * 際のキーになります。
	 *
	 * @param string $profile プロファイル名、省略された場合は<code>default</code>
	 */
	public function __construct($profile = 'default')
	{
		$this->headers = new ArrayList();
		$this->replyToList = new ArrayList();
		$this->toList = new ArrayList();
		$this->ccList = new ArrayList();
		$this->bccList = new ArrayList();

		/* @var $profile Config */
		$profile = System::getProperty('mailer/'.$profile);
		if ($profile !== null) {
			$smtphost = $profile->getProperty('SMTP');
			if ($smtphost !== null)
				ini_set('SMTP', $smtphost);
			$this->setSubject($profile->getProperty('subject'));
			$this->setFrom($profile->getProperty('from'));
			$this->addTo($profile->getProperty('to'));
			$this->addBcc($profile->getProperty('bcc'));
			$this->addCc($profile->getProperty('cc'));
			$this->addReplyTo($profile->getProperty('replyTo'));
			$this->textEncoding = $profile->getProperty('textEncoding');
			$this->textTransferEncoding = $profile->getProperty('textTransferEncoding');
			$this->headerEncoding = $profile->getProperty('headerEncoding');
			$this->headerTransferEncoding = $profile->getProperty('headerTransferEncoding');
		}
	}

	/**
	 * @return string
	 */
	protected function createBundary()
	{
		return md5(uniqid(time()));
	}

	/**
	 * メールを送信します、From アドレスが指定されていまたはphp.iniに指定がない場合は例外がスロー
	 * されます。
	 *
	 * @since 1.0 2007/03/03
	 * @throws SendMailException メール送信に失敗
	 */
	public function send()
	{
//		mb_internal_encoding("utf-8");
//		mb_language("japanese");

		$log = LogFactory::getLogger();
		$headers = new StringBuffer();
		$body = new StringBuffer();

		// 送信先アドレス
		$toaddress = $this->concatAddress($this->toList);

		// 送信元アドレス
		if ($this->from !== null) {
			$headers->appendln("From: ".$this->encodeHeaderAddress($this->from));
		}

		// 返信先アドレス (Reply-to)
		$temp = $this->concatAddress($this->replyToList);
		if ($temp !== null) {
			$headers->appendln("Reply-to: ".$temp);
		}

		// CCアドレス
		$temp = $this->concatAddress($this->ccList);
		if ($temp !== null) {
			$headers->appendln("Cc: ".$temp);
		}

		// BCCアドレス
		$temp = $this->concatAddress($this->bccList);
		if ($temp !== null) {
			$headers->appendln("Bcc: ".$temp);
		}

		// Date
		if ($this->sentDate !== null) {
			$headers->appendln("Date: ".$this->toRFCDate($this->sentDate));
		}

		// 件名
		$encoding = System::firstNotEmpty($this->subject->getEncoding(), $this->headerEncoding);
		$transferEncoding = System::firstNotEmpty($this->subject->getTransferEncoding(), $this->headerTransferEncoding);
		$subject = $this->encodeHeader($this->subject->getValue(), $encoding, $transferEncoding);

		// 追加ヘッダー
		$headers->appendln("X-Mailer: PHP/".System::getPHPVersion());
		$headers->appendln("MIME-version: 1.0");
		foreach ($this->headers as $headerEntry) {	/* @var $headerEntry Entry */
			/* @var $header Header */
			$header = $headerEntry->getValue();
			$encoding = System::firstNotEmpty($header->getEncoding(), $this->headerEncoding);
			$transferEncoding = System::firstNotEmpty($header->getTransferEncoding(), $this->headerTransferEncoding);
			$headers->appendln($headerEntry->getKey().": ".$this->encodeHeader($header->getValue(), $encoding, $transferEncoding));
		}

		if ($this->body === null) {
			// Dummy contents.
			$headers->appendln('Content-Type: text/plain');
			$headers->appendln('');
			$body->appendln('');
		} else if ($this->body instanceof ContentBody) {
			/* @var $content ContentBody */
			$content = $this->body;
			$encoding = System::firstNotEmpty($content->getEncoding(), $this->textEncoding);
			$transferEncoding = System::firstNotEmpty($content->getTransferEncoding(), $this->textTransferEncoding);
			$headers->appendln('Content-Type: '.$content->getContentType().'; charset='.$encoding);
			$headers->appendln('Content-Transfer-Encoding: '. $transferEncoding);
			$body->appendln($this->encodeContentBody($content->getContent(), $encoding, $transferEncoding));
		} else if ($this->body instanceof MultipartBody) {
			// Create bundary
			$boundary = $this->createBundary();
			$this->createMultipart($boundary, $headers, $body, $this->body);
		}
		// TODO : 化ける文字を変換

		// TODO : 携帯に絵文字を送る場合は以下
//$headers .= "Content-Type: text/plain; charset=Shift-JIS\\n";
//$headers .= "Content-Transfer-Encoding: base64″;

//	$log->debug('To:'.$toaddress);
//$log->debug($headers->toString());
		// Send mail.
		$ret = @mail($toaddress, $subject, $body->toString(), $headers->toString());
		if ($ret === false) {
			$message = String::format("Fail to send mail : {0}", @$php_errormsg);
			throw new SendMailException($message);
		}

/*
　$msg = "";
　$from = $email;
　$header = "From: $from\n";
　$header .= "Reply-To: $from\n";
　$header .= "X-Mailer: PHP/".phpversion()."\n";
　$header .= "MIME-version: 1.0\n";
　if(file_exists($upfile)){ //アップファイルがあれば
　　$header .= "Content-Type: multipart/mixed;\n";
　　$header .= "\tboundary=\"$boundary\"\n";
　　$msg .= "This is a multi-part message in MIME format.\n\n";
　　$msg .= "--$boundary\n";
　　$msg .= "Content-Type: text/plain; charset=ISO-2022-JP\n";
　　$msg .= "Content-Transfer-Encoding: 7bit\n\n";
　}else{
　　$header .= "Content-Type: text/plain; charset=ISO-2022-JP\n";
　　$header .= "Content-Transfer-Encoding: 7bit\n";
　}
　$msg .= "お名前 = $name\n";
　$msg .= "E-mail = $email\n";
　if($hp){ $msg .= "HomePage = $hp\n"; }
　if($area){ $msg .= "住んでる地域 = $area\n"; }
　if($tel){ $msg .= "お電話 = $tel\n"; }
　if($comment){
　　$comment = str_replace("<br />", "\n", $comment);
　　$msg .= "ご意見 = $comment\n";
　}
　if(file_exists($upfile)){
　　$fp = fopen($upfile, "r") or die("error"); //ファイルの読み込み
　　$contents = fread($fp, filesize($upfile));
　　fclose($fp);
　　$f_encoded = chunk_split(base64_encode($contents)); //エンコードして分割
　　$msg .= "\n\n--$boundary\n";
　　$msg .= "Content-Type: " . $upfile_type . ";\n";
　　$msg .= "\tname=\"$upfile_name\"\n";
　　$msg .= "Content-Transfer-Encoding: base64\n";
　　$msg .= "Content-Disposition: attachment;\n";
　　$msg .= "\tfilename=\"$upfile_name\"\n\n";
　　$msg .= "$f_encoded\n";
　　$msg .= "--$boundary--";
　}
　if(mail($to, $subject, $msg, $header)){ //ファイル添付に対応
　　echo "メールが正常に送信されました(^o^)丿<br><br>\n";
　　echo "<INPUT type=button name=close value=閉じる onclick=window.close()>\n";
　}else{
　　echo "メールの送信に失敗しました(>_<)もう一度やり直して下さい。<br><br>\n";
　　echo "<INPUT type=button name=close value=閉じる onclick=window.close()>\n";
　}
}
?>


		// BODY
		// Windows の場合はドットを２つに置き換える
		//$text = str_replace("\n.", "\n..", $text);
/*
user@example.com
user@example.com, anotheruser@example.com
User <user@example.com>
User <user@example.com>, Another User <anotheruser@example.com>
 */

//mb_encode_mimeheader()

	}

	/**
	 * @param string $boundary
	 * @param StringBuffer $headers
	 * @param StringBuffer $body
	 * @param MultipartBody $content
	 */
	protected function createMultipart($boundary, StringBuffer $headers, StringBuffer $body, MultipartBody $content)
	{
		$headers->appendln('Content-Type: ' . $content->getMultipartType().';');
		$headers->appendln(" boundary=\"".$boundary."\"");
		$body->appendln("This is a multi-part message in MIME format.");
		foreach ($content->getMultipartBodies() as $childBody) {
			if ($childBody instanceof ContentBody) {
				$body->appendln("--{$boundary}");
				$body->append  ('Content-Type: '.$childBody->getContentType());
				if ($childBody->getEncoding() !== null) {
					$body->append  ('; charset='.$childBody->getEncoding());
				}
				$body->appendln('');
				$body->appendln('Content-Transfer-Encoding: '.$childBody->getTransferEncoding());
				if ($childBody->getFileName() !== null) {
					$body->appendln('Content-Disposition: attachment;');
					$body->appendln(" filename=\"".$childBody->getFileName().'"');
				}
				$body->appendln('');
				$body->appendln($this->encodeContentBody($childBody->getContent(),
						$childBody->getEncoding(), $childBody->getTransferEncoding()));
			} else if ($childBody instanceof MultipartBody) {
				$this->createMultipart($boundary, $headers, $body, $childBody);
			}
		}
		$body->appendln("--{$boundary}--");
	}


	/**
	 * @param $datetime
	 * @return string
	 */
	public function toRFCDate(Timestamp $datetime)
	{
	    $tz = $datetime->format('Z');
	    $tzs = ($tz < 0) ? '-' : '+';
	    $tz = abs($tz);
	    $tz = (int)($tz/3600)*100 + ($tz%3600)/60;
	    $result = sprintf("%s %s%04d", $datetime->format('D, j M Y H:i:s'), $tzs, $tz);

	    return $result;
	}

	/**
	 * @param ArrayList $toaddress <Address>
	 */
	protected function concatAddress(ArrayList $addressList)
	{
		$toaddress = null;
		foreach ($addressList as $address) {	/* @var $to Address */
			if ($toaddress !== null)
				$toaddress .= ', ';
			$toaddress .= $this->encodeHeaderAddress($address);
		}
		return $toaddress;
	}

	/**
	 * BODYコンテンツをエンコードおよび転送エンコードで変換する
	 * @param string $text
	 * @param string $encoding
	 * @param string $transferEncoding
	 */
	protected function encodeContentBody($text, $encoding, $transferEncoding)
	{
		if ($encoding !== null) {
			$text = mb_convert_encoding($text, $encoding, 'utf-8');
		}
		if ($transferEncoding === 'base64') {
			$text = base64_encode($text);
		}
		return chunk_split($text);
	}

	/**
	 * @param string $string
	 * @return ArrayList
	 */
	protected function parseRFCAddress($string)
	{
		// FIXME : ダブルクオートで囲むものもある
		$array = new ArrayList();
		if (String::isNotEmpty($string)) {
			$addresses = explode(',', $string);
			foreach ($addresses as $address) {
				$matches = array();
				if (preg_match('/^(.*?) <(.*?)>$/', $address, $matches)) {
					$array->add(new Address($matches[2], $matches[1]));
				} else {
					$array->add(new Address($address));
				}
			}
		}
		return $array;
	}

	/**
	 * Address => "Jone <jone@mail.com>"
	 * @param string $value
	 */
	protected function encodeHeaderAddress(Address $address)
	{
		if ($address->getName() !== null) {
			$encoding = System::firstNotEmpty($address->getEncoding(), $this->headerEncoding);
			$transferEncoding = System::firstNotEmpty($address->getTransferEncoding(), $this->headerTransferEncoding);
			return $this->encodeHeader($address->getName(), $encoding, $transferEncoding) . ' <'.$address->getAddress().'>';
		} else {
			return $address->getAddress();
		}
	}

	/**
	 * @param string $value
	 * @param string $encoding
	 * @param string $transferEncoding
	 */
	protected function encodeHeader($text, $encoding, $transferEncoding)
	{
		return mb_encode_mimeheader($text, $encoding, $transferEncoding);
	}

	/**
	 * 件名を設定します
	 * @param string $subject 件名
	 * @param string $encoding エンコーディング、省略された場合は、{@link #setHeaderEncoding}で設定
	 * 			されたものが使用されます
	 * @param string $transferEncoding
	 */
	public function setSubject($subject, $encoding = null, $transferEncoding = null)
	{
		$this->subject = new Header($subject, $encoding, $transferEncoding);
	}

	/**
  	 * テキスト形式の本文を追加する
	 * @param string $text 本文
	 * @param string $contentType コンテントタイプ、HTMLメールを送信する場合は "text/html"
	 */
	public function setTextBody($text, $contentType = 'text/plain', $encoding = null, $transferEncoding = null)
	{
		$this->body = new ContentBody($text, $contentType, null, $encoding, $transferEncoding);
	}

	/**
  	 * ファイル形式の本文を追加する、通常の添付ファイルを実現したい場合は、{@link #setMultipartBody}を使用して
  	 * ください。
  	 *
	 * @param string $filepath 追加するファイルのパス
	 * @param string $contentType コンテントタイプ
	 * @param string $fileName ファイル名
	 * @param string $transferEncoding 転送エンコーディング
	 */
	public function setFileBody($filepath, $contentType, $fileName = null, $transferEncoding = null)
	{
		$fileName = $fileName === null ? File::getBaseName($filepath) : $fileName;
		$content = File::getContents($filepath);
		$this->body = new ContentBody($content, $contentType, $fileName, $encoding, $transferEncoding);
	}

	/**
	 * マルチパートコンテンツを追加する
	 * <pre>
	 * $body = new MultipartBody(MultipartBody::MULTIPART_ALTERNATIVE);
	 * $body->addTextBody('Hellow world!');
	 * $mailer->setMultipartBody($body);
	 * </pre>
	 *
	 * @param MultipartBody $body
	 */
	public function setMultipartBody(MultipartBody $body)
	{
		$this->body = $body;
	}


	/**
	 * <pre>
	 * $mailer = new Mailer();
	 * $mailer->setFrom('sample@mail.com');
	 * $mailer->setFrom('Jone <sample@mail.com>');
	 * $mailer->setFrom('sample@mail.com', 'Jone');
	 * </pre>
	 * @param string $address
	 * @param string $name
	 */
	public function setFrom($address, $name = null, $encoding = null, $transferEncoding = null)
	{
		$list = ($name !== null ? new AraryList(new Address($address, $name, $encoding, $transferEncoding)) : $this->parseRFCAddress($address));
		$this->from = $list->firstElement();
	}

	/**
	 * 返信先アドレスを追加します。
	 * <pre>
	 * $mailer = new Mailer();
	 * $mailer->addReplyTo('sample@mail.com');
	 * $mailer->addReplyTo('Jone <sample@mail.com>');
	 * $mailer->addReplyTo('sample@mail.com', 'Jone');
	 * $mailer->addReplyTo('Jone <sample@mail.com>, Beck <sample2@mail.com>');
	 * </pre>
	 * @param string $address
	 * @param string $name
	 */
	public function addReplyTo($address, $name = null, $encoding = null, $transferEncoding = null)
	{
		$list = ($name !== null ? new ArrayList(new Address($address, $name, $encoding, $transferEncoding)) : $this->parseRFCAddress($address));
		$this->replyToList = ArrayUtils::merge($this->replyToList, $list);
	}

	/**
	 * 送信先アドレスを追加します、省略された場合は現在のプロファイルに設定されているものがあれば
	 * それを使用します。
	 * <pre>
	 * $mailer = new barge\mail\Mailer();
	 * $mailer->addTo('jone@sample.com');
	 * $mailer->addTo('jone@sample.com', 'Jone');
	 * $mailer->addTo('Jone <jone@sample.com>');
	 * $mailer->addTo('Jone <jone@sample.com>, Keliy <keliy@sample.com>');
	 * </pre>
	 * @param string $address
	 * @param string $name
	 * @param string $encoding
	 * @param string $transferEncoding
	 */
	public function addTo($address, $name = null, $encoding = null, $transferEncoding = null)
	{
		$list = ($name !== null ? new ArrayList(new Address($address, $name, $encoding, $transferEncoding)) : $this->parseRFCAddress($address));
		$this->toList = ArrayUtils::merge($this->toList, $list);
	}

	/**
	 * ＢＣＣメールアドレスを設定します、省略された場合は現在のプロファイルに設定されているものがあれば
	 * それを使用します。
	 *
	 * @param string $address
	 * @param string $name
	 * @param string $encoding
	 * @param string $transferEncoding
	 */
	public function addBcc($address, $name = null, $encoding = null, $transferEncoding = null)
	{
		$list = ($name !== null ? new ArrayList(new Address($address, $name, $encoding, $transferEncoding)) : $this->parseRFCAddress($address));
		$this->bccList = ArrayUtils::merge($this->bccList, $list);
	}

	/**
	 * CCアドレスを追加します
	 * @param string $address
	 * @param string $name
	 * @param string $encoding
	 * @param string $transferEncoding
	 */
	public function addCc($address, $name = null, $encoding = null, $transferEncoding = null)
	{
		$list = ($name !== null ? new ArrayList(new Address($address, $name, $encoding, $transferEncoding)) : $this->parseRFCAddress($address));
		$this->ccList = ArrayUtils::merge($this->ccList, $list);
	}

	/**
	 * @param Timestamp $value
	 */
	public function setSentDate(Timestamp $value)
	{
		$this->sentDate = $value;
	}

	/**
	 * @param string $value
	 */
	public function setTextEncoding($value)
	{
		$this->textEncoding = $value;
	}

	/**
	 * @param string $value
	 */
	public function setTextTransferEncoding($value)
	{
		$this->textTransferEncoding = $value;
	}

	/**
	 * @param string $value
	 */
	public function setHeaderEncoding($value)
	{
		$this->headerEncoding = $value;
	}

	/**
	 * @param string $value
	 */
	public function setHeaderTransferEncoding($value)
	{
		$this->headerTransferEncoding = $value;
	}

	/**
	 * 追加のヘッダーを追加します、例えば優先度（X-Priolity）などのような個別の
	 * アプリケーションで設定するようなヘッダーを設定します。
	 *
	 * <pre>
	 * $mailer = new Mailer();
	 * $mailer->addHeader('X-Priority', 1);
	 * </pre>
	 *
	 * @param string $value
	 */
	public function addHeader($key, $value, $encoding, $transferEncoding)
	{
		$this->headers->add(new Entry($key, new Header($value, $encoding, $transferEncoding)));
	}


}
